/*
 *  Copyright 2009 Jamie Gennis <jgennis@gmail.com>.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */

package com.google.code.gwt.remoteaction.group.client;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Singleton;

/**
 * An opaque representation of a group of actions as created by.
 * 
 * @author jgennis
 */
public class ActionGroup {

  /**
   * The factory for creating {@link ActionGroup} instances.
   * 
   * Note that applications should not create {@link ActionGroup} instances
   * themselves, but rather should create them via
   * {@link GroupingActionFilter#beginActionGroup(AsyncCallback)}.
   * 
   * @author jgennis
   */
  @Singleton
  public static class Factory {

    ActionGroup create(AsyncCallback<Void> callback) {
      return new ActionGroup(callback);
    }
  }

  final AsyncCallback<Void> callback;

  int numActions = 0;

  int numSuccesses = 0;

  boolean hasFailed = false;

  boolean isEnded = false;

  /**
   * Construct a new {@code ActionGroup} with a given callback object.
   * 
   * @param callback the callback to call when execution of the action group has
   *          completed
   */
  ActionGroup(AsyncCallback<Void> callback) {
    this.callback = callback;
  }

  /**
   * Add an action invocation to the action group.
   * 
   * This must be called before {@link #endActionGroup()}.
   */
  void addAction() {
    assert !isEnded;
    numActions++;
  }

  /**
   * Stop collecting actions for the action group.
   */
  void endActionGroup() {
    isEnded = true;
    if (numSuccesses == numActions)
      callback.onSuccess(null);
  }

  /**
   * Notify the action group of a successfully executed action.
   */
  void onSuccess() {
    numSuccesses++;
    if (isEnded && (numSuccesses == numActions))
      callback.onSuccess(null);
  }

  /**
   * Notify the action group of an unsuccessfully executed action.
   * 
   * @param caught the throwable from the action execution failure
   */
  void onFailure(Throwable caught) {
    if (!hasFailed) {
      hasFailed = true;
      callback.onFailure(caught);
    }
  }
}
